from math import *
from numpy import *

def regla_trapecio_simple(f, x_i, x_f):
    h = (x_f - x_i)
    return (h/2)*(f(x_f) + f(x_i))

def regla_trapecio_compuesta(f, x_i, x_f, n):
    h = (x_f - x_i)/n
    sumatorio = 0
    for k in range(2, n + 1):
        sumatorio += f(x_i + ((k - 1)*h))
    return (h/2)*(f(x_i) + f(x_f)) + h*sumatorio

def regla_simpson_tercio(f, x_i, x_f):
    h = (x_f - x_i)/2
    x_m = (x_i + x_f)/2
    return (h/3)*(f(x_i) + f(x_f) + 4*f(x_m))

def regla_simpson_tercio_compuesta(f, x_i, x_f):
    return ((x_f - x_i)/6)*(f(x_i) + f(x_f) + 4*f((x_i + x_f)/2))

def regla_simpson_tres_octavos(f, x_i, x_f):
    h = (b-a)/3
    return ((3*h)/8)*(f(x_i) + f(x_f) + 3*f(x_i + h) + 3*f(x_i + 2*h))

# EJERCICIO 1 =================================================================
print("Ejercicio 1 " + "="*50)
print("")

a, b = 0, 0.8

def f(x):
    return 400*x**5 - 900*x**4 + 675*x**3 - 200*x**2 + 25*x + 0.2

print(f"Integral entre a = {a:.5f} y b = {b:.5f}\nRegla del trapecio:  \t{regla_trapecio_simple(f,a,b):.5f}\nRegla de Simpson 1/3: \t{regla_simpson_tercio(f, a, b):.5f}")

# EJERCICIO 2 =================================================================
print("")
print("Ejercicio 2 " + "="*50)
print("")

xi, xf = 1, 3
intervalo = 5

def funcion(x):
    return 1/(1 + x**2)

print(f"Regla del trapecio compuesta ({intervalo} intervalos)\nel resultado obtenido para la integral I es {regla_trapecio_compuesta(funcion, xi, xf, intervalo):.7f}")

# EJERCICIO 3 =================================================================
print("")
print("Ejercicio 3 " + "="*50)
print("")

a, b = 0, 0.8

def funcion(x):
    return 400*x**5 - 900*x**4 + 675*x**3 - 200*x**2 + 25*x + 0.2

print(f"Integral entre a = {a:.5f} b = {b:.5f}\nRegla de Simpson 3/8: {regla_simpson_tres_octavos(funcion, a, b):.5f}")

# EJERCICIO 4 =================================================================
print("")
print("Ejercicio 4 " + "="*50)
print("")

a, b = 0, 1.35
n, diferencia = 1, 1e-8

def f(x):
    return x**3 - 3*x**2 - x + 3

I_old = regla_trapecio_compuesta(f, a, b, n)
while True:
    n += 1
    I_new = regla_trapecio_compuesta(f, a, b, n)
    if abs(I_new - I_old)<=diferencia:
        break
    I_old = I_new

print(f"Regla del trapecio compuesta\nLa integral entre a = {a:.2f} y b = {b:.2f} es: {I_new:.9f}")